//
//  GMGridView.m
//  GMGridView
//
//  Created by Gulam Moledina on 11-10-09.
//  Copyright (C) 2011 by Gulam Moledina.
//
//  Latest code can be found on GitHub: https://github.com/gmoledina/GMGridView
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#import <QuartzCore/QuartzCore.h>
#import "GMGridView.h"
#import "GMGridViewCell+Extended.h"
#import "GMGridViewLayoutStrategies.h"
#import "UIGestureRecognizer+GMGridViewAdditions.h"
//#import "RecommendCell.h"


static const NSUInteger kTagOffset = 50;
static const CGFloat kDefaultAnimationDuration = 0.3;
static const UIViewAnimationOptions kDefaultAnimationOptions = UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction;


#pragma mark - Private interface
@interface GMGridView () <UIGestureRecognizerDelegate, UIScrollViewDelegate>{
    // Views
    UIScrollView *_scrollView;
    
    // Sorting Gestures
    UIPanGestureRecognizer       *_sortingPanGesture;
    UILongPressGestureRecognizer *_sortingLongPressGesture;
    
    // Tap gestures
    UITapGestureRecognizer       *_tapGesture;
    
    // General vars
    NSInteger _numberTotalItems;
    CGSize    _itemSize;
    NSMutableSet *_reusableCells;
    
    // Moving (sorting) control vars
    GMGridViewCell *_sortMovingItem;
    NSInteger _sortFuturePosition;
    BOOL _autoScrollActive;
    
    CGPoint _minPossibleContentOffset;
    CGPoint _maxPossibleContentOffset;
    
    BOOL _rotationActive;
    
    NSInteger _numberTotalItemsPerPage;       // Default is 0 - When GMGridViewLayoutStrategyType　is GMGridViewLayoutHorizontalPagedLTR or GMGridViewLayoutHorizontalPagedTTB, will reset numberTotalItemsPage
}

@property (nonatomic, readonly) BOOL itemsSubviewsCacheIsValid;
@property (nonatomic, retain) NSArray *itemSubviewsCache;
@property (atomic) NSInteger firstPositionLoaded;
@property (atomic) NSInteger lastPositionLoaded;
@property (nonatomic, assign) NSInteger   currentPage;


// Gestures
- (void)sortingPanGestureUpdated:(UIPanGestureRecognizer *)panGesture;
- (void)sortingLongPressGestureUpdated:(UILongPressGestureRecognizer *)longPressGesture;
- (void)tapGestureUpdated:(UITapGestureRecognizer *)tapGesture;

// Sorting movement control
- (void)sortingMoveDidStartAtPoint:(CGPoint)point;
- (void)sortingMoveDidContinueToPoint:(CGPoint)point;
- (void)sortingMoveDidStopAtPoint:(CGPoint)point;
- (void)sortingAutoScrollMovementCheck;

// Helpers & more
- (void)resetItemSize;
- (void)recomputeSize;
- (void)relayoutItemsAnimated:(BOOL)animated;
- (NSArray *)itemSubviews;
- (GMGridViewCell *)cellForItemAtIndex:(NSInteger)position;
- (GMGridViewCell *)newItemSubViewForPosition:(NSInteger)position;
- (NSInteger)positionForItemSubview:(GMGridViewCell *)view;
- (void)setSubviewsCacheAsInvalid;

// Lazy loading
- (void)loadRequiredItems;
- (void)cleanupUnseenItems;
- (void)queueReusableCell:(GMGridViewCell *)cell;

// Memory warning
- (void)receivedMemoryWarningNotification:(NSNotification *)notification;

// Rotation handling
- (void)willRotate:(NSNotification *)notification;

@end



#pragma mark - Implementation
@implementation GMGridView

@synthesize sortingDelegate = _sortingDelegate;
@synthesize dataSource = _dataSource;
@synthesize actionDelegate = _actionDelegate;

@synthesize mainSuperView = _mainSuperView;
@synthesize layoutStrategy = _layoutStrategy;
@synthesize itemHorizontalSpacing = _itemHorizontalSpacing;
@synthesize itemVerticalSpacing = _itemVerticalSpacing;
@synthesize style = _style;
@synthesize minimumPressDuration;
@synthesize centerGrid = _centerGrid;
@synthesize minEdgeInsets = _minEdgeInsets;
@synthesize showFullSizeViewWithAlphaWhenTransforming;
@synthesize editing = _editing;
@synthesize scrollView = _scrollView;

@synthesize itemsSubviewsCacheIsValid = _itemsSubviewsCacheIsValid;
@synthesize itemSubviewsCache = _itemSubviewsCache;

@synthesize firstPositionLoaded = _firstPositionLoaded;
@synthesize lastPositionLoaded = _lastPositionLoaded;
@synthesize currentPage = _currentPage;

//////////////////////////////////////////////////////////////
#pragma mark Constructors and destructor
//////////////////////////////////////////////////////////////

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
    
    _mainSuperView = nil;
    
    [_scrollView release],_scrollView = nil;
    
    [_tapGesture release],_tapGesture = nil;
    [_sortingPanGesture release],_sortingPanGesture = nil;
    [_sortingLongPressGesture release],_sortingLongPressGesture = nil;
    
    [_reusableCells release],_reusableCells = nil;
    [_sortMovingItem release],_sortMovingItem = nil;
    
    [_layoutStrategy release],_layoutStrategy = nil;
    [_itemSubviewsCache release],_itemSubviewsCache = nil;
    [super dealloc];
}

- (id)initWithFrame:(CGRect)frame 
{
    if ((self = [super initWithFrame:frame])) 
    {
        _scrollView = [[UIScrollView alloc] initWithFrame:[self bounds]];
        _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _scrollView.backgroundColor = [UIColor clearColor];
        _scrollView.delegate = self;
        _scrollView.bounces = NO;
        _scrollView.pagingEnabled = YES;
        _scrollView.showsHorizontalScrollIndicator = NO;
        _scrollView.showsVerticalScrollIndicator = NO;
        [self addSubview:_scrollView];
        
        //Tap gesture
        _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureUpdated:)];
        _tapGesture.delegate = self;
        _tapGesture.numberOfTapsRequired = 1;
        _tapGesture.numberOfTouchesRequired = 1;
        [_scrollView addGestureRecognizer:_tapGesture];
        
        //////////////////////
        // Sorting gestures
        _sortingPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(sortingPanGestureUpdated:)];
        _sortingPanGesture.delegate = self;
        [_scrollView addGestureRecognizer:_sortingPanGesture];
        
        _sortingLongPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(sortingLongPressGestureUpdated:)];
        _sortingLongPressGesture.delegate = self;
        [_scrollView addGestureRecognizer:_sortingLongPressGesture];

        // Gesture dependencies
        UIPanGestureRecognizer *panGestureRecognizer = nil;
        if ([_scrollView respondsToSelector:@selector(panGestureRecognizer)]) // iOS5 only
        { 
            panGestureRecognizer = _scrollView.panGestureRecognizer;
        }
        else 
        {
            for (UIGestureRecognizer *gestureRecognizer in _scrollView.gestureRecognizers) 
            { 
                if ([gestureRecognizer  isKindOfClass:NSClassFromString(@"UIScrollViewPanGestureRecognizer")]) 
                {
                    panGestureRecognizer = (UIPanGestureRecognizer *) gestureRecognizer;
                }
            }
        }
        [panGestureRecognizer setMaximumNumberOfTouches:1];
        [panGestureRecognizer requireGestureRecognizerToFail:_sortingPanGesture];

        [_tapGesture requireGestureRecognizerToFail:_sortingLongPressGesture];

        self.layoutStrategy = [GMGridViewLayoutStrategyFactory strategyFromType:GMGridViewLayoutHorizontalPagedLTR];
        
        self.mainSuperView = self;
        self.itemHorizontalSpacing = 10;
        self.itemVerticalSpacing = 10;
        self.style = GMGridViewStylePush;
        self.minimumPressDuration = 1.0;
        self.showFullSizeViewWithAlphaWhenTransforming = YES;
        self.minEdgeInsets = UIEdgeInsetsMake(5, 5, 5, 5);
        self.clipsToBounds = NO;
        self.currentPage = 0;
        
        _sortFuturePosition = GMGV_INVALID_POSITION;
        _itemSize = CGSizeZero;
        _numberTotalItemsPerPage = 0;
        
        _minPossibleContentOffset = CGPointMake(0, 0);
        _maxPossibleContentOffset = CGPointMake(0, 0);
        
        _reusableCells = [[NSMutableSet alloc] init];
        
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(receivedMemoryWarningNotification:)
                                                     name:UIApplicationDidReceiveMemoryWarningNotification
                                                   object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(willRotate:)
                                                     name:UIApplicationWillChangeStatusBarOrientationNotification
                                                   object:nil];
    }
    return self;
}

#pragma mark -  Layout
- (void)layoutSubviews 
{
    [super layoutSubviews];

    void (^layoutBlock)(void) = ^{
//        [self resetItemSize];
        [self recomputeSize];
        [self relayoutItemsAnimated:NO];
        [self loadRequiredItems];
    };
    
    if (_rotationActive) 
    {
        _rotationActive = NO;
        [UIView animateWithDuration:0 
                              delay:0
                            options:UIViewAnimationOptionOverrideInheritedDuration
                         animations:^{
                             layoutBlock();
                         }
                         completion:^(BOOL finished) {
                             [self scrollRectToVisiblePageAtIndex:_currentPage animated:NO];
                         }];
    }
    else 
    {
        layoutBlock();
    }
}

#pragma mark -  setters / getters
- (void)setCurrentPage:(NSInteger)currentPage{
    _currentPage = currentPage;
    
    if ([self.actionDelegate respondsToSelector:@selector(gmGridView:pageNumberInGridView:)]) {
        [self.actionDelegate gmGridView:self pageNumberInGridView:_currentPage];
    }
}

- (void)setItemSubviewsCache:(NSArray *)itemSubviewsCache{
    if (_itemSubviewsCache != itemSubviewsCache ) {
        [_itemSubviewsCache release],_itemSubviewsCache = nil;
        _itemSubviewsCache = [[NSArray alloc] initWithArray:itemSubviewsCache];
    }
    
}

- (void)setDataSource:(NSObject<GMGridViewDataSource> *)dataSource
{
    _dataSource = dataSource;
    [self reloadData];
}

- (void)setMainSuperView:(UIView *)mainSuperView
{
    _mainSuperView = mainSuperView != nil ? mainSuperView : self;
}

- (void)setLayoutStrategy:(id<GMGridViewLayoutStrategy>)layoutStrategy
{
    if (_layoutStrategy != layoutStrategy) {
        [_layoutStrategy release],_layoutStrategy = nil;
        _layoutStrategy = [layoutStrategy retain];
    }
    
    _scrollView.pagingEnabled = [[self.layoutStrategy class] requiresEnablingPaging];
}

- (void)setItemHorizontalSpacing:(NSInteger)itemHorizontalSpacing
{
    _itemHorizontalSpacing = itemHorizontalSpacing;
}

- (void)setItemVerticalSpacing:(NSInteger)itemVerticalSpacing
{
    _itemVerticalSpacing = itemVerticalSpacing;
}

- (void)setCenterGrid:(BOOL)centerGrid
{
    _centerGrid = centerGrid;
}

- (void)setMinEdgeInsets:(UIEdgeInsets)minEdgeInsets
{
    _minEdgeInsets = minEdgeInsets;
}

- (void)setMinimumPressDuration:(CFTimeInterval)duration
{
    _sortingLongPressGesture.minimumPressDuration = duration;
}

- (CFTimeInterval)minimumPressDuration
{
    return _sortingLongPressGesture.minimumPressDuration;
}

- (void)setEditing:(BOOL)editing
{
    if ([self.dataSource respondsToSelector:@selector(gmGridView:deleteItemAtIndex:)]
        && ((self.isEditing && !editing) || (!self.isEditing && editing))) 
    {
        for (GMGridViewCell *cell in [self itemSubviews]) 
        {
            if (cell.editEnabled) {
                [cell setEditing:editing];
            }
            
            if (!editing) {
                [cell showDeleteButton:NO];
            }
        }
        
        _editing = editing;
    }
}

- (void)setShowsVerticalScrollIndicator:(BOOL)showsVerticalScroll 
{
  _scrollView.showsVerticalScrollIndicator = showsVerticalScroll;
}

- (BOOL)showsVerticalScrollIndicator 
{
  return _scrollView.showsVerticalScrollIndicator;
}

- (void)setShowsHorizontalScrollIndicator:(BOOL)showsHorizontalScrollIndicator 
{
  _scrollView.showsHorizontalScrollIndicator = showsHorizontalScrollIndicator;
}

- (BOOL)showsHorizontalScrollIndicator 
{
  return _scrollView.showsHorizontalScrollIndicator;
}

#pragma mark - UIScrollView delegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{     
    [self loadRequiredItems];
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    CGFloat pageWidth = _scrollView.frame.size.width;
    self.currentPage = floor((_scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
}

#pragma mark - GestureRecognizer delegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([[touch view] isKindOfClass:[UIImageView class]] || [[touch view] isKindOfClass:[GMGridViewCell class]] || [[touch view] isKindOfClass:[UIScrollView class]]) {
        return YES;
    }
    return NO;
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{    
    BOOL valid = YES;
    BOOL isScrolling = _scrollView.isDragging || _scrollView.isDecelerating;
    
    if (gestureRecognizer == _tapGesture) 
    {
//        valid = !isScrolling && !self.isEditing && [self.layoutStrategy itemPositionFromLocation:locationTouch] != GMGV_INVALID_POSITION;
        valid = !isScrolling && !self.isEditing && (self.actionDelegate != nil);
        if (self.isEditing) {
            for (GMGridViewCell *cell in [self itemSubviews]){
                if (cell.editEnabled) {
                    [cell showDeleteButton:NO];
                }
            }
            self.editing = NO;
            if ([self.actionDelegate respondsToSelector:@selector(gmGridViewDidEndEditing:)]) {
                [self.actionDelegate gmGridViewDidEndEditing:self];
            }
        }

    }
    else if (gestureRecognizer == _sortingLongPressGesture)
    {
//        valid = !isScrolling && !self.isEditing && (self.sortingDelegate != nil);
        if (self.isEditing) {
            self.editing = NO;
        }
        
        valid = !isScrolling && (self.sortingDelegate != nil);

    }
    else if (gestureRecognizer == _sortingPanGesture)
    {
        valid = (_sortMovingItem != nil && [_sortingLongPressGesture hasRecognizedValidGesture]);
    }
    return valid;
}

#pragma mark - Sorting gestures & logic
- (void)sortingLongPressGestureUpdated:(UILongPressGestureRecognizer *)longPressGesture
{
    switch (longPressGesture.state) 
    {
        case UIGestureRecognizerStateBegan:
        {
            if (!_sortMovingItem) 
            { 
                CGPoint location = [longPressGesture locationInView:_scrollView];
                
                NSInteger position = [self.layoutStrategy itemPositionFromLocation:location];
                
                GMGridViewCell *item = [self cellForItemAtIndex:position];
                if (!item.editEnabled) {
                    return;
                }
                
                for (GMGridViewCell *cell in [self itemSubviews])
                {
                    if (cell.editEnabled && cell != item && !cell.isEditing) {
                        [cell setEditing:YES];
                        [cell showDeleteButton:YES];
                    }
                }

                
                if (position != GMGV_INVALID_POSITION)
                {
                    [self sortingMoveDidStartAtPoint:location];
                }
            }
            
            break;
        }
        case UIGestureRecognizerStateRecognized:
        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateFailed:
        {
            [_sortingPanGesture end];
            
            if (_sortMovingItem) 
            {
                CGPoint location = [longPressGesture locationInView:_scrollView];
                [self sortingMoveDidStopAtPoint:location];
            }
            
            break;
        }
        default:
            break;
    }
}

- (void)sortingPanGestureUpdated:(UIPanGestureRecognizer *)panGesture
{
    switch (panGesture.state)
    {
        case UIGestureRecognizerStateEnded:
        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateFailed:
        {
            _autoScrollActive = NO;
            _scrollView.scrollEnabled = YES;
            break;
        }
        case UIGestureRecognizerStateBegan:
        {            
            _autoScrollActive = YES;
//            [self sortingAutoScrollMovementCheck];
            
            _scrollView.scrollEnabled = NO;
            break;
        }
        case UIGestureRecognizerStateChanged:
        {
            CGPoint translation = [panGesture translationInView:_scrollView];
            CGPoint offset = translation;
            CGPoint locationInScroll = [panGesture locationInView:_scrollView];
            
            _scrollView.scrollEnabled = NO;            
            if (locationInScroll.x>0 && locationInScroll.x < _scrollView.bounds.size.width*ceil(_numberTotalItems*1.0/_numberTotalItemsPerPage)) {
                CGFloat  leftDistance = fabsf(locationInScroll.x-_scrollView.contentOffset.x);
                CGFloat  rightDistance = fabsf(locationInScroll.x-_scrollView.contentOffset.x-_scrollView.bounds.size.width);

                NSInteger  page = 0;
                BOOL  neeScroll = NO;
                if (leftDistance < _itemSize.width/3) {
                    neeScroll = YES;
                    page = _currentPage-1;
                }else if (rightDistance < _itemSize.width/3){
                    neeScroll = YES;
                    page = _currentPage+1;
                }
 
                if (neeScroll) {
                    [_scrollView scrollRectToVisible:CGRectMake(page*_scrollView.bounds.size.width, _scrollView.bounds.origin.y, _scrollView.bounds.size.width, _scrollView.bounds.size.height) animated:YES];
                    [self performSelector:@selector(delaySetCurrentPage:)
                               withObject:[NSNumber numberWithInteger:page]
                               afterDelay:1.0];
                    
                }
 
            }
            
            _sortMovingItem.transform = CGAffineTransformMakeTranslation(offset.x, offset.y);
            [self sortingMoveDidContinueToPoint:locationInScroll];
            
            break;
        }
        default:
            break;
    }
}

- (void)delaySetCurrentPage:(NSNumber *)page
{
    self.currentPage = [page integerValue];
}

- (void)sortingAutoScrollMovementCheck
{
    if (_sortMovingItem && _autoScrollActive) 
    {
        CGPoint locationInMainView = [_sortingPanGesture locationInView:self];
//        CGPoint locationInScroll   = [_sortingPanGesture locationInView:_scrollView];

        CGFloat threshhold = _itemSize.height;
        CGPoint offset = _scrollView.contentOffset;
        
        // Going down
        if (locationInMainView.x + threshhold > self.bounds.size.width) 
        {
            offset.x += _itemSize.width / 2;
            
            if (offset.x > _maxPossibleContentOffset.x) 
            {
                offset.x = _maxPossibleContentOffset.x;
            }
        }
        // Going up
        else if (locationInMainView.x - threshhold <= 0) 
        {
            offset.x -= _itemSize.width / 2;
            
            if (offset.x < _minPossibleContentOffset.x) 
            {
                offset.x = _minPossibleContentOffset.x;
            }
        }
        
        // Going right
        if (locationInMainView.y + threshhold > self.bounds.size.height) 
        {
            offset.y += _itemSize.height / 2;
            
            if (offset.y > _maxPossibleContentOffset.y) 
            {
                offset.y = _maxPossibleContentOffset.y;
            }
        }
        // Going left
        else if (locationInMainView.y - threshhold <= 0) 
        {
            offset.y -= _itemSize.height / 2;
            
            if (offset.y < _minPossibleContentOffset.y) 
            {
                offset.y = _minPossibleContentOffset.y;
            }
        }
        
        if (offset.x != _scrollView.contentOffset.x || offset.y != _scrollView.contentOffset.y) 
        {
            [UIView animateWithDuration:kDefaultAnimationDuration 
                                  delay:0
                                options:kDefaultAnimationOptions
                             animations:^{
                                 _scrollView.contentOffset = offset;
                             }
                             completion:^(BOOL finished){
                                 
                                 _scrollView.contentOffset = offset;
                                 
                                 if (_autoScrollActive) 
                                 {
//                                     [self sortingMoveDidContinueToPoint:locationInScroll];
                                 }
                                 
                                 [self sortingAutoScrollMovementCheck];
                             }
             ];
        }
        else
        {
            [self performSelector:@selector(sortingAutoScrollMovementCheck) withObject:nil afterDelay:0.5];
        }
    }
}

- (void)sortingMoveDidStartAtPoint:(CGPoint)point
{
    NSInteger position = [self.layoutStrategy itemPositionFromLocation:point];
    
    GMGridViewCell *item = [self cellForItemAtIndex:position];
    
    [_scrollView bringSubviewToFront:item];
    _sortMovingItem = item;
    
    CGRect frameInMainView = [_scrollView convertRect:_sortMovingItem.frame toView:self.mainSuperView];
    
    [_sortMovingItem retain];
    [_sortMovingItem removeFromSuperview];
    _sortMovingItem.frame = frameInMainView;
    [self.mainSuperView addSubview:_sortMovingItem];
    [_sortMovingItem release];
    
    _sortFuturePosition = _sortMovingItem.tag - kTagOffset;

    _sortMovingItem.deleteButton.alpha = 1.0f;
    _sortMovingItem.tag = 0;
    
    if ([self.sortingDelegate respondsToSelector:@selector(gmGridView:didStartMovingCell:)])
    {
        [self.sortingDelegate gmGridView:self didStartMovingCell:_sortMovingItem];
    }

}

- (void)sortingMoveDidStopAtPoint:(CGPoint)point
{
    _sortMovingItem.tag = _sortFuturePosition + kTagOffset;
    
    CGRect frameInScroll = [self.mainSuperView convertRect:_sortMovingItem.frame toView:_scrollView];
    
    [_sortMovingItem retain];
    [_sortMovingItem removeFromSuperview];
    _sortMovingItem.frame = frameInScroll;
    [_scrollView addSubview:_sortMovingItem];
    [_sortMovingItem release];
    
    CGPoint newOrigin = [self.layoutStrategy originForItemAtPosition:_sortFuturePosition];
    CGRect newFrame = CGRectMake(newOrigin.x, newOrigin.y, _itemSize.width, _itemSize.height);
    
    [UIView animateWithDuration:kDefaultAnimationDuration 
                          delay:0
                        options:0
                     animations:^{
                         _sortMovingItem.transform = CGAffineTransformIdentity;
                         _sortMovingItem.frame = newFrame;
                     }
                     completion:^(BOOL finished){
                         if ([self.sortingDelegate respondsToSelector:@selector(gmGridView:didEndMovingCell:)])
                         {
                             [self.sortingDelegate gmGridView:self didEndMovingCell:_sortMovingItem];
                         }

                         _sortMovingItem = nil;
                         _sortFuturePosition = GMGV_INVALID_POSITION;
                         self.editing = YES;
                         [self setSubviewsCacheAsInvalid];
                     }
     ];
}

- (NSInteger)getChangedNumForItem:(NSInteger)fromIndex
                          toIndex:(NSInteger)toIndex
                        isForward:(BOOL)isForward
{
    NSInteger  intervalNum = 1;
    if (isForward) {
        for (NSInteger i=fromIndex; i>toIndex; i--) {
            GMGridViewCell *cell = [self cellForItemAtIndex:i];
            if (i == fromIndex && !cell.editEnabled) {
                return 0;
            }else{
                GMGridViewCell *cell1 = [self cellForItemAtIndex:i-1];
                if ( i-1 == toIndex || cell1.editEnabled || cell1 == nil) {
                    return intervalNum;
                }

                if (!cell1.editEnabled) {
                    intervalNum ++;
                }
            }
        }
        
    }else{
        for (NSInteger i=fromIndex; i<toIndex; i++){
            GMGridViewCell *cell = [self cellForItemAtIndex:i];
            if (i == fromIndex && !cell.editEnabled) {
                return 0;
            }else{
                GMGridViewCell *cell1 = [self cellForItemAtIndex:i+1];
                if ( i+1 == toIndex || cell1.editEnabled || cell1 == nil) {
                    return intervalNum;
                }
                
                if (!cell1.editEnabled) {
                    intervalNum ++;
                }
            }
        }
    }
    return intervalNum;
}

- (void)sortingMoveDidContinueToPoint:(CGPoint)point
{
    int originalPosition = [self.layoutStrategy itemPositionFromLocation:point];
    int position = originalPosition<_numberTotalItems?originalPosition:_numberTotalItems-1;
    
    int tag = position + kTagOffset;
    NSInteger  placeholderCount = _numberTotalItemsPerPage==12?6:9;
        
    if (position != GMGV_INVALID_POSITION && position != _sortFuturePosition && position>=placeholderCount)
    {
        BOOL positionTaken = NO;
        
        for (UIView *v in [self itemSubviews])
        {
            if (v != _sortMovingItem && v.tag == tag && [(GMGridViewCell *)v editEnabled])
            {
                positionTaken = YES;
                break;
            }
        }
        
        if (positionTaken)
        {
            switch (self.style) 
            {
                case GMGridViewStylePush:
                {
                    if (position > _sortFuturePosition)
                    {
                        for (UIView *v in [self itemSubviews])
                        {
                            if (v != _sortMovingItem) {
                                GMGridViewCell *cell = (GMGridViewCell *)v;
                                if (cell.editEnabled) {
                                    cell.editing = YES;
                                    cell.deleteButton.alpha = 1.0f;
                                }
                                
                                if ((v.tag == tag || (v.tag < tag && v.tag >= _sortFuturePosition + kTagOffset)))
                                {
                                    
                                    v.tag = v.tag - [self getChangedNumForItem:v.tag-kTagOffset
                                                                       toIndex:_sortFuturePosition
                                                                     isForward:YES];
                                    [_scrollView sendSubviewToBack:v];
                                }
                            }
                        }
                    }
                    else
                    {
                        for (UIView *v in [self itemSubviews])
                        {
                            if (v != _sortMovingItem) {
                                GMGridViewCell *cell = (GMGridViewCell *)v;
                                if (cell.editEnabled) {
                                    cell.editing = YES;
                                    cell.deleteButton.alpha = 1.0f;
                                }
                                
                                if ((v.tag == tag || (v.tag > tag && v.tag <= _sortFuturePosition + kTagOffset)) )
                                {
                                    v.tag = v.tag + [self getChangedNumForItem:v.tag-kTagOffset
                                                                       toIndex:_sortFuturePosition
                                                                     isForward:NO];
                                    [_scrollView sendSubviewToBack:v];
                                }
                            }
                            
                        }
                    }
                    
                    if ([self.sortingDelegate respondsToSelector:@selector(gmGridView:moveItemAtIndex:toIndex:)]) {
                        [self.sortingDelegate gmGridView:self moveItemAtIndex:_sortFuturePosition toIndex:position];
                    }
                    
                    [self relayoutItemsAnimated:YES];
                    _sortFuturePosition = position;

                    break;
                }
                case GMGridViewStyleSwap:
                default:
                {
                    if (_sortMovingItem) 
                    {
                        UIView *v = [self cellForItemAtIndex:position];
                                                
                        v.tag = _sortFuturePosition + kTagOffset;
                        CGPoint origin = [self.layoutStrategy originForItemAtPosition:_sortFuturePosition];
                        
                        [UIView animateWithDuration:kDefaultAnimationDuration 
                                              delay:0
                                            options:kDefaultAnimationOptions
                                         animations:^{
                                             v.frame = CGRectMake(origin.x, origin.y, _itemSize.width, _itemSize.height);
                                         }
                                         completion:nil
                         ];
                    }
                    
                    if ([self.sortingDelegate respondsToSelector:@selector(gmGridView:exchangeItemAtIndex:withItemAtIndex:)]) {
                                            [self.sortingDelegate gmGridView:self exchangeItemAtIndex:_sortFuturePosition withItemAtIndex:position];
                    }

                    _sortFuturePosition = position;
                    break;
                }
            }
        }
    }
}

- (void)endEditingStatus
{
    for (GMGridViewCell *cell in [self itemSubviews]){
        if (cell.editEnabled) {
            [cell showDeleteButton:NO];
        }
    }
    self.editing = NO;

}

#pragma mark - UITapGestureRecognizer
- (void)tapGestureUpdated:(UITapGestureRecognizer *)tapGesture
{
    CGPoint locationTouch = [_tapGesture locationInView:_scrollView];
    NSInteger position = [self.layoutStrategy itemPositionFromLocation:locationTouch];
    
    
    if (_isDestop) {
        NSInteger  placeholderCount = _numberTotalItemsPerPage==12?6:9;
        if (position != GMGV_INVALID_POSITION && position>=placeholderCount && position<_numberTotalItems)
            {
                if ([self.actionDelegate respondsToSelector:@selector(gmGridView:didSelectItemAtIndex:)]) {
                    [self.actionDelegate gmGridView:self didSelectItemAtIndex:position];
                }
            }
        return;
    }
    if (position != GMGV_INVALID_POSITION && position<_numberTotalItems){
            if ([self.actionDelegate respondsToSelector:@selector(gmGridView:didSelectItemAtIndex:)]) {
                [self.actionDelegate gmGridView:self didSelectItemAtIndex:position];
            }
        }

}

#pragma mark - private methods
- (void)setSubviewsCacheAsInvalid
{
    _itemsSubviewsCacheIsValid = NO;
}

- (GMGridViewCell *)newItemSubViewForPosition:(NSInteger)position
{
    GMGridViewCell *cell = [[self.dataSource gmGridView:self cellForItemAtIndex:position] retain];
    CGPoint origin = [self.layoutStrategy originForItemAtPosition:position];
    CGRect frame = CGRectMake(origin.x, origin.y, _itemSize.width, _itemSize.height);
    
    // To make sure the frame is not animated
    [UIView animateWithDuration:0 
                          delay:0 
                        options:kDefaultAnimationOptions | UIViewAnimationOptionOverrideInheritedDuration 
                     animations:^{
                         cell.frame = frame;
                         cell.contentView.frame = cell.bounds;
                     } 
                     completion:nil];
    
    cell.tag = position + kTagOffset;
    if (cell.editEnabled) {
        cell.editing = self.editing;
    }
    
    cell.deleteBlock = ^(GMGridViewCell *aCell)
    {
        NSInteger index = [self positionForItemSubview:aCell];
        if (index != GMGV_INVALID_POSITION) 
        {
            if ([self.dataSource respondsToSelector:@selector(gmGridView:deleteItemAtIndex:)]) {
                [self.dataSource gmGridView:self deleteItemAtIndex:index];
                [self removeObjectAtIndex:index];

            }
        }
    };
    
    return [cell autorelease];
}

- (NSArray *)itemSubviews
{
    NSArray *subviews = nil;

    if (self.itemsSubviewsCacheIsValid) 
    {
        subviews = [NSArray arrayWithArray:self.itemSubviewsCache];
    }
    else
    {
        @synchronized(_scrollView)
        {
            NSMutableArray *itemSubViews = [NSMutableArray arrayWithCapacity:_numberTotalItems];
            
            for (UIView * v in [_scrollView subviews]) 
            {
                if ([v isKindOfClass:[GMGridViewCell class]]) 
                {
                    [itemSubViews addObject:v];
                }
            }            
            subviews = [NSArray arrayWithArray:itemSubViews];
        
            self.itemSubviewsCache = subviews;
            
            _itemsSubviewsCacheIsValid = YES;
        }
    }
    
    return subviews;
}

- (GMGridViewCell *)cellForItemAtIndex:(NSInteger)position
{
    GMGridViewCell *view = nil;
    
    for (GMGridViewCell *v in [self itemSubviews]) 
    {
        if (v.tag == position + kTagOffset) 
        {
            view = v;
            break;
        }
    }
    
    return view;
}

- (NSInteger)positionForItemSubview:(GMGridViewCell *)view
{
    return view.tag >= kTagOffset ? view.tag - kTagOffset : GMGV_INVALID_POSITION;
}

- (void)recomputeSize
{
    [self.layoutStrategy setupItemSize:_itemSize andItemHSpacing:self.itemHorizontalSpacing andItemVSpacing:self.itemVerticalSpacing withMinEdgeInsets:self.minEdgeInsets andCenteredGrid:self.centerGrid];
    [self.layoutStrategy rebaseWithItemCount:_numberTotalItems insideOfBounds:self.bounds];
    
    
    if ([self.layoutStrategy isKindOfClass:[GMGridViewLayoutHorizontalPagedStrategy class]]) {
        _numberTotalItemsPerPage = [(GMGridViewLayoutHorizontalPagedStrategy *)self.layoutStrategy numberOfItemsPerPage];
    }
    
    CGSize contentSize = [self.layoutStrategy contentSize];
    
    _minPossibleContentOffset = CGPointMake(0, 0);
    _maxPossibleContentOffset = CGPointMake(contentSize.width - _scrollView.bounds.size.width + _scrollView.contentInset.right, contentSize.height - _scrollView.bounds.size.height + _scrollView.contentInset.bottom);
    
    [UIView animateWithDuration:kDefaultAnimationDuration
                          delay:0
                        options:kDefaultAnimationOptions 
                     animations:^{
                         if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) 
                         {
                             _scrollView.contentSize = contentSize;
                             
                         }
                     }
                     completion:nil];
}

- (void)relayoutItemsAnimated:(BOOL)animated
{    
    void (^layoutBlock)(void) = ^{
        for (UIView *view in [self itemSubviews])
        {        
            if (view != _sortMovingItem)
            {
                NSInteger index = view.tag - kTagOffset;
                CGPoint origin = [self.layoutStrategy originForItemAtPosition:index];
                CGRect newFrame = CGRectMake(origin.x, origin.y, _itemSize.width, _itemSize.height);
                // IF statement added for performance reasons (Time Profiling in instruments)
                if (!CGRectEqualToRect(newFrame, view.frame)) 
                {
                    view.frame = newFrame;
                    [view setNeedsLayout];
                }
            }
        }
    };
    
    if (animated) {
        [UIView animateWithDuration:kDefaultAnimationDuration
                              delay:0
                            options:kDefaultAnimationOptions
                         animations:^{
                             layoutBlock();
                         }
                         completion:^(BOOL finished) {

                         }];
    }else {
        layoutBlock();
    }
}


#pragma mark - loading/destroying items & reusing cells
- (void)loadRequiredItems
{
    NSRange rangeOfPositions = [self.layoutStrategy rangeOfPositionsInBoundsFromOffset: _scrollView.contentOffset];
    NSRange loadedPositionsRange = NSMakeRange(self.firstPositionLoaded, self.lastPositionLoaded - self.firstPositionLoaded);
    
    BOOL forceLoad = self.firstPositionLoaded == GMGV_INVALID_POSITION || self.lastPositionLoaded == GMGV_INVALID_POSITION;

    NSInteger positionToLoad;
    
    for (int i = 0; i < rangeOfPositions.length; i++) 
    {
        positionToLoad = i + rangeOfPositions.location;
        
        if ((forceLoad || !NSLocationInRange(positionToLoad, loadedPositionsRange)) && positionToLoad < _numberTotalItems) 
        {
            if (![self cellForItemAtIndex:positionToLoad]) 
            {
                GMGridViewCell *cell = [[self newItemSubViewForPosition:positionToLoad] retain];
                if (self.editing && cell.editing) {
                    cell.deleteButton.alpha = 1.0;
                }else{
                    cell.deleteButton.alpha = 0.0;
                }
                [_scrollView addSubview:cell];
                [cell release];
            }
        }
    }
    
    self.firstPositionLoaded = self.firstPositionLoaded == GMGV_INVALID_POSITION ? rangeOfPositions.location : MIN(self.firstPositionLoaded, rangeOfPositions.location);
    self.lastPositionLoaded  = self.lastPositionLoaded == GMGV_INVALID_POSITION ? NSMaxRange(rangeOfPositions) : MAX(self.lastPositionLoaded, rangeOfPositions.length + rangeOfPositions.location);
    
    if ([self.actionDelegate respondsToSelector:@selector(gmGridView:pageNumberInGridView:)]) {
        [self.actionDelegate gmGridView:self pageNumberInGridView:_currentPage];
    }
    
    [self setSubviewsCacheAsInvalid];
    
    [self cleanupUnseenItems];
}


- (void)cleanupUnseenItems
{
    dispatch_async(dispatch_get_main_queue(), ^{
        
        NSRange rangeOfPositions = [self.layoutStrategy rangeOfPositionsInBoundsFromOffset: _scrollView.contentOffset];
        GMGridViewCell *cell;
        
        if (rangeOfPositions.location > self.firstPositionLoaded) 
        {
            for (int i = self.firstPositionLoaded; i < rangeOfPositions.location; i++) 
            {
                cell = [self cellForItemAtIndex:i];
                if(cell)
                {
                    cell.deleteButton.alpha = 0.0f;
                    cell.editing = NO;
                    
                    [self queueReusableCell:cell];
                    [cell removeFromSuperview];
                }
            }
            
            self.firstPositionLoaded = rangeOfPositions.location;
            [self setSubviewsCacheAsInvalid];
        }
        
        if (NSMaxRange(rangeOfPositions) < self.lastPositionLoaded) 
        {
            for (int i = NSMaxRange(rangeOfPositions); i <= self.lastPositionLoaded; i++)
            {
                cell = [self cellForItemAtIndex:i];
                if(cell)
                {
                    cell.deleteButton.alpha = 0.0f;
                    cell.editing = NO;
                    
                    [self queueReusableCell:cell];
                    [cell removeFromSuperview];
                }
            }
            
            self.lastPositionLoaded = NSMaxRange(rangeOfPositions);
            [self setSubviewsCacheAsInvalid];
        }
        
    });
}

- (void)queueReusableCell:(GMGridViewCell *)cell
{
    if (cell) 
    {
        [cell prepareForReuse];
        cell.alpha = 1;
        cell.backgroundColor = [UIColor clearColor];
        [_reusableCells addObject:cell];
    }
}

- (GMGridViewCell *)dequeueReusableCell
{
    GMGridViewCell *cell = [_reusableCells anyObject];
    
    [cell retain];
    if (cell) 
    {
        [_reusableCells removeObject:cell];
    }
    
    return [cell autorelease];
}

- (void)receivedMemoryWarningNotification:(NSNotification *)notification
{
    [self cleanupUnseenItems];
    [_reusableCells removeAllObjects];
}

- (void)willRotate:(NSNotification *)notification
{
    _rotationActive = YES;
}

#pragma mark - public methods
- (void)resetItemSize
{
    NSInteger  space = 9;
    NSInteger  itemSpaceH = 6;
    NSInteger  itemSpaceV = 6;
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if (UIInterfaceOrientationIsPortrait(orientation)) {
        space = 2;
    }
    
    _itemVerticalSpacing = itemSpaceH;
    _itemVerticalSpacing = itemSpaceV;
    _minEdgeInsets = UIEdgeInsetsMake(space, space, space, space);
    _itemSize = [self.dataSource sizeForItemsInGMGridView:self];
}

- (void)reloadData
{
    CGPoint previousContentOffset = _scrollView.contentOffset;

    [[self itemSubviews] enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop){
        [(UIView *)obj removeFromSuperview];
    }];
    
    self.firstPositionLoaded = GMGV_INVALID_POSITION;
    self.lastPositionLoaded  = GMGV_INVALID_POSITION;
    
    [self setSubviewsCacheAsInvalid];
    
    NSUInteger numberItems = [self.dataSource numberOfItemsInGMGridView:self];    
    _itemSize = [self.dataSource sizeForItemsInGMGridView:self];

    _numberTotalItems = numberItems;
    
    [self recomputeSize];
    
    CGPoint newContentOffset = CGPointMake(MIN(_maxPossibleContentOffset.x, previousContentOffset.x), MIN(_maxPossibleContentOffset.y, previousContentOffset.y));
    newContentOffset = CGPointMake(MAX(newContentOffset.x, _minPossibleContentOffset.x), MAX(newContentOffset.y, _minPossibleContentOffset.y));
                                        
    _scrollView.contentOffset = newContentOffset;
    
    [self loadRequiredItems];
    
    [self setSubviewsCacheAsInvalid];
    [self setNeedsLayout];
}

- (void)reloadObjectAtIndex:(NSInteger)index
{    
    NSAssert((index >= 0 && index < _numberTotalItems), @"Invalid index");
    
    UIView *currentView = [self cellForItemAtIndex:index];
    
    GMGridViewCell *cell = [[self newItemSubViewForPosition:index] retain];
    CGPoint origin = [self.layoutStrategy originForItemAtPosition:index];
    cell.frame = CGRectMake(origin.x, origin.y, _itemSize.width, _itemSize.height);
    cell.alpha = 0;
    [_scrollView addSubview:cell];
    
    currentView.tag = kTagOffset - 1;
    
    [UIView animateWithDuration:kDefaultAnimationDuration 
                          delay:0
                        options:kDefaultAnimationOptions
                     animations:^{
                         currentView.alpha = 0;
                         cell.alpha = 1;
                     } 
                     completion:^(BOOL finished){
                         [currentView removeFromSuperview];
                         [cell release];
                     }
     ];
    
    
    [self setSubviewsCacheAsInvalid];
}

- (void)scrollRectToVisiblePageAtIndex:(NSInteger)index animated:(BOOL)animated
{
    [_scrollView setContentOffset:CGPointMake(index*_scrollView.bounds.size.width, 0)
                         animated:animated];
}

- (void)scrollToObjectAtIndex:(NSInteger)index animated:(BOOL)animated
{
    index = MAX(0, index);
    index = MIN(index, _numberTotalItems);

    CGPoint origin = [self.layoutStrategy originForItemAtPosition:index];
    CGRect scrollToRect = CGRectMake(origin.x, origin.y, _itemSize.width, _itemSize.height);
    
    if (_scrollView.pagingEnabled) 
    {
        CGPoint originScroll = CGPointZero;
        
        CGSize pageSize = CGSizeMake(_scrollView.bounds.size.width  - _scrollView.contentInset.left - _scrollView.contentInset.right, 
                                     _scrollView.bounds.size.height - _scrollView.contentInset.top  - _scrollView.contentInset.bottom);
        
        while (originScroll.x + pageSize.width < origin.x) 
        {
            originScroll.x += pageSize.width;
        }
        
        while (originScroll.y + pageSize.height < origin.y) 
        {
            originScroll.y += pageSize.height;
        }
        
        scrollToRect = CGRectMake(originScroll.x, originScroll.y, pageSize.width, pageSize.height);
    }
    
    // Better performance animating ourselves instead of using animated:YES in scrollRectToVisible
    [_scrollView scrollRectToVisible:scrollToRect animated:animated];

}

- (void)insertObjectAtIndex:(NSInteger)index
{
    NSAssert((index >= 0 && index <= _numberTotalItems), @"Invalid index specified");
    
    _numberTotalItems++;
    _currentPage = index/_numberTotalItemsPerPage;
    
    [self.layoutStrategy rebaseWithItemCount:_numberTotalItems insideOfBounds:self.bounds];    
    CGSize contentSize = [self.layoutStrategy contentSize];
    
    if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize))
    {
        _scrollView.contentSize = contentSize;
        
    }
    
    [self layoutSubviews];
    
    [self scrollToObjectAtIndex:index animated:YES];
    
}

- (void)removeObjectAtIndex:(NSInteger)index
{
    NSAssert((index >= 0 && index < _numberTotalItems), @"Invalid index specified");

    GMGridViewCell *cell = [self cellForItemAtIndex:index];    
    for (int i = index + 1; i < _numberTotalItems; i++)
    {
        GMGridViewCell *oldView = [self cellForItemAtIndex:i];
        if (_numberTotalItems <= _numberTotalItemsPerPage) {
            oldView.tag = oldView.tag - 1;
        }else{
            if (oldView.editEnabled && self.isEditing) {
                oldView.editing = YES;
                oldView.deleteButton.alpha = 1.0f;
            }
            oldView.tag = oldView.tag - [self getChangedNumForItem:i toIndex:index isForward:YES];
        }
    }
    
    cell.tag = kTagOffset - 1;
    _numberTotalItems--;
    [self recomputeSize];

    [UIView animateWithDuration:kDefaultAnimationDuration
                          delay:0
                        options:kDefaultAnimationOptions
                     animations:^{
                         cell.contentView.alpha = 0.3;
                         cell.alpha = 0;
                         
                         //删除时，滑动到删除项目所在的page
//                         [self scrollToObjectAtIndex:index animated:YES];
                         
                     } 
                     completion:^(BOOL finished){
                         cell.contentView.alpha = 1;
                         [self queueReusableCell:cell];
                         [cell removeFromSuperview];
                         
                         self.firstPositionLoaded = self.lastPositionLoaded = GMGV_INVALID_POSITION;
                         [self loadRequiredItems];
                         [self relayoutItemsAnimated:YES];
                         
                         CGFloat pageWidth = _scrollView.frame.size.width;
                         self.currentPage = floor((_scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
                         
                     }
     ];
    
}

- (void)swapObjectAtIndex:(NSInteger)index1 withObjectAtIndex:(NSInteger)index2
{
    NSAssert((index1 >= 0 && index1 < _numberTotalItems), @"Invalid index1 specified");
    NSAssert((index2 >= 0 && index2 < _numberTotalItems), @"Invalid index2 specified");
        
    GMGridViewCell *view1 = [self cellForItemAtIndex:index1];
    GMGridViewCell *view2 = [self cellForItemAtIndex:index2];
    
    view1.tag = index2 + kTagOffset;
    view2.tag = index1 + kTagOffset;

    CGPoint view1Origin = [self.layoutStrategy originForItemAtPosition:index2];
    CGPoint view2Origin = [self.layoutStrategy originForItemAtPosition:index1];
    
    view1.frame = CGRectMake(view1Origin.x, view1Origin.y, _itemSize.width, _itemSize.height);
    view2.frame = CGRectMake(view2Origin.x, view2Origin.y, _itemSize.width, _itemSize.height);

    
    CGRect visibleRect = CGRectMake(_scrollView.contentOffset.x,
                                    _scrollView.contentOffset.y, 
                                    _scrollView.contentSize.width, 
                                    _scrollView.contentSize.height);
    
    // Better performance animating ourselves instead of using animated:YES in scrollRectToVisible
    [UIView animateWithDuration:kDefaultAnimationDuration 
                          delay:0
                        options:kDefaultAnimationOptions
                     animations:^{
                         if (!CGRectIntersectsRect(view2.frame, visibleRect)) 
                         {
                             [self scrollToObjectAtIndex:index1 animated:YES];
                         }
                         else if (!CGRectIntersectsRect(view1.frame, visibleRect)) 
                         {
                             [self scrollToObjectAtIndex:index2 animated:YES];
                         }
                     } 
                     completion:^(BOOL finished){

                     }
     ];
}


@end
